/*
* @Author: michael
* @Date:   2016-07-26 23:15:23
* @Last Modified by:   michael
* @Last Modified time: 2016-07-28 01:44:33
*/
#ifndef PART_TM4C123GH6PM
#define PART_TM4C123GH6PM
#endif

#ifndef TARGET_IS_BLIZZARD_RA1
#define TARGET_IS_BLIZZARD_RA1
#endif
#include "stdint.h"
#include "stdbool.h"
#include "inc/hw_gpio.h"
#include "inc/hw_i2c.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"

#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"

#include "LDC1314.h"
#include "usart/usart.h"
#include "key.h"
#include "lcd.h"
#include "num_str.h"
#include "pwm/timer_pwm.h"

#define LDC1314_I2C_ADDRESS (0x2A)      // pin ADDR  LO:0x2A  HI:0x2B
#define delay_ms(x)     SysCtlDelay(SysCtlClockGet()/3000*x)

static void ldc1314_init(void);
static void ldc1314_tx(uint8_t reg_addr, uint16_t data);
static void ldc1314_rx(uint8_t reg_addr, uint16_t *data);
static void ldc1314_cali(void);
static void ldc1314_test(void);


struct Ldc1314 ldc1314 =
{
    .fac_line   = 3,
    .fac_coin   = 30,

    .init       = ldc1314_init,
    .tx         = ldc1314_tx,
    .rx         = ldc1314_rx,
    .cali       = ldc1314_cali,
    .test       = ldc1314_test,
};

void IntGPIODHandler(void)
{
    if( GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_1) == 0<<1 )
    {
//      ldc1314.rx(LDC1314_CMD_DATA_MSB_CH0, &ldc1314.data_ch[0]);
    }
    GPIOIntClear(GPIO_PORTD_BASE, GPIO_INT_PIN_1);
}

void IntI2C0Handler(void)
{
    I2CMasterIntClear(I2C0_BASE);
}

void IntTimer2AHandler(void)
{
    TimerIntClear( TIMER2_BASE, TIMER_TIMA_TIMEOUT );
    uint16_t    i;
    static uint16_t tmp;
    static uint16_t tmp_last;

    ldc1314.rx(LDC1314_CMD_DATA_MSB_CH0, &ldc1314.data_ch[0]);
    ldc1314.rx(LDC1314_CMD_DATA_MSB_CH1, &ldc1314.data_ch[1]);
    ldc1314.rx(LDC1314_CMD_DATA_MSB_CH2, &ldc1314.data_ch[2]);
    ldc1314.rx(LDC1314_CMD_DATA_MSB_CH3, &ldc1314.data_ch[3]);
    ldc1314.data_offset[0] = ldc1314.data_ch[0] - ldc1314.data_base[0];
    ldc1314.data_offset[1] = ldc1314.data_ch[1] - ldc1314.data_base[1];
    ldc1314.data_offset[2] = ldc1314.data_ch[2] - ldc1314.data_base[2];
    ldc1314.data_offset[3] = ldc1314.data_ch[3] - ldc1314.data_base[3];
    tmp = 0;
    for(i=0; i<4; i++)
    {
        if ( abs(ldc1314.data_offset[i]) > ldc1314.fac_line )
            tmp |= 1<<i;
        if ( abs(ldc1314.data_offset[i]) > ldc1314.fac_coin )
            tmp |= 0x10;
    }
    modUart.tx_data = 0;
    if ( tmp == 0 ) tmp = tmp_last & 0x09;
    if ( tmp&0x08 ) modUart.tx_data = 4;
    else if ( tmp&0x01 ) modUart.tx_data = 1;
    else if ( tmp&0x04 ) modUart.tx_data = 3;
    else if ( tmp&0x02 ) modUart.tx_data = 2;
    if ( tmp&0x10 ) modUart.tx_data += 10;
    if( modUart.isRunning ) modUart.tx(modUart.tx_data);
    tmp_last = tmp;
}


static void ldc1314_init_gpio(void)
{
    /* PD0 -> ADDR:LO    PD1 -> INTB    PD2 -> SD:LO */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_0|GPIO_PIN_2);
    GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, 0<<0 );
    GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, 0<<2 );
    GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_1);
    GPIOIntTypeSet(GPIO_PORTD_BASE, GPIO_PIN_1, GPIO_FALLING_EDGE);
    GPIOIntClear(GPIO_PORTD_BASE,GPIO_INT_PIN_1);
    IntEnable(INT_GPIOD);
    // GPIOIntEnable(GPIO_PORTD_BASE, GPIO_INT_PIN_1);
}

static void ldc1314_init_i2c(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), true);
    I2CMasterEnable(I2C0_BASE);

    I2CIntRegister(I2C0_BASE, IntI2C0Handler);
//  I2CMasterIntEnable(I2C0_BASE);
    I2CMasterIntClear(I2C0_BASE);
}

static void ldc1314_init_timer(void)
{   /* 40MHz/200/4000 = 50Hz */
    ROM_SysCtlPeripheralEnable( SYSCTL_PERIPH_TIMER2 );
    ROM_TimerPrescaleSet( TIMER2_BASE, TIMER_A, 250 );      // split pair only
    ROM_TimerConfigure( TIMER2_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC );
    ROM_TimerControlEvent( TIMER2_BASE, TIMER_A, TIMER_EVENT_POS_EDGE );
    ROM_TimerLoadSet( TIMER2_BASE, TIMER_A, 6400-1 );
    TimerIntRegister( TIMER2_BASE, TIMER_A, IntTimer2AHandler );
    ROM_IntEnable( INT_TIMER2A );
    ROM_TimerIntEnable( TIMER2_BASE, TIMER_TIMA_TIMEOUT );
    ROM_TimerIntClear( TIMER2_BASE, TIMER_TIMA_TIMEOUT );
    ROM_TimerEnable( TIMER2_BASE, TIMER_A );
}

static void ldc1314_init_config(void)
{
    GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, 1<<2 );
    delay_ms(10);
    GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, 0<<2 );
    delay_ms(10);
    ldc1314.tx(LDC1314_CMD_RCOUNT_CH0, 0x0800);
    ldc1314.tx(LDC1314_CMD_RCOUNT_CH1, 0x0800);
    ldc1314.tx(LDC1314_CMD_RCOUNT_CH2, 0x0800);
    ldc1314.tx(LDC1314_CMD_RCOUNT_CH3, 0x0800);
    ldc1314.tx(LDC1314_CMD_SETTLECOUNT_CH0, 0x0200);
    ldc1314.tx(LDC1314_CMD_SETTLECOUNT_CH1, 0x0200);
    ldc1314.tx(LDC1314_CMD_SETTLECOUNT_CH2, 0x0200);
    ldc1314.tx(LDC1314_CMD_SETTLECOUNT_CH3, 0x0200);
    ldc1314.tx(LDC1314_CMD_CLOCK_DIVIDERS_CH0, 0x1018);     // 20pf: 0x100C 330pf: 0x1019
    ldc1314.tx(LDC1314_CMD_CLOCK_DIVIDERS_CH1, 0x1018);
    ldc1314.tx(LDC1314_CMD_CLOCK_DIVIDERS_CH2, 0x1018);
    ldc1314.tx(LDC1314_CMD_CLOCK_DIVIDERS_CH3, 0x1018);
//  ldc1314.tx(LDC1314_CMD_ERROR_CONFIG, 0x0001);           // DRDY to INT
    ldc1314.tx(LDC1314_CMD_CONFIG, 0x1401);                 // CLKIN pin disable
    ldc1314.tx(LDC1314_CMD_MUX_CONFIG, 0xC20C);             // 4 CH: 0xC20C
//  ldc1314.tx(LDC1314_CMD_SYSTEM_CLOCK_CONFIG, 0x0200);    // default, divide by 2
    ldc1314.tx(LDC1314_CMD_DRIVE_CURRENT_CH0, 0xF800);
    ldc1314.tx(LDC1314_CMD_DRIVE_CURRENT_CH1, 0xF800);
    ldc1314.tx(LDC1314_CMD_DRIVE_CURRENT_CH2, 0xF800);
    ldc1314.tx(LDC1314_CMD_DRIVE_CURRENT_CH3, 0xF800);
}

static void ldc1314_test(void) {
    uint8_t key = EMPTY_INPUT;
    TFT_Clear(BLACK);
    uint8_t data_offsets[4][16];
    uint8_t i;
    uint8_t num[5];
    while(key != KEY_BACK)
    {   
        key = check_key();
        for (i = 0; i < 4; i++) {
            uint322str(ldc1314.data_offset[i], data_offsets[i]);
            TFT_String(5, 30*i+5, WHITE, BLACK, data_offsets[i]);
        }
        uint322str(modUart.tx_data, num);
        TFT_String(5, 155, WHITE, BLACK, num);
//         UARTSend((uint8_t *)"hahahah", 7);
    }
}

static void ldc1314_init(void)
{
    ldc1314_init_gpio();
    ldc1314_init_i2c();
    ldc1314_init_config();
    modUart.uartInit();
    ldc1314_init_timer();
}

static void ldc1314_tx(uint8_t reg_addr, uint16_t data)
{
    I2CMasterSlaveAddrSet(I2C0_BASE, LDC1314_I2C_ADDRESS, false);
    I2CMasterDataPut(I2C0_BASE, reg_addr);
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    while(I2CMasterBusy(I2C0_BASE));
    I2CMasterDataPut(I2C0_BASE, (data>>8)&0xFF);
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
    while(I2CMasterBusy(I2C0_BASE));
    I2CMasterDataPut(I2C0_BASE, data&0xFF);
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
    while(I2CMasterBusy(I2C0_BASE));
}

static void ldc1314_rx(uint8_t reg_addr, uint16_t *data)
{
    static uint8_t rx_buffer[2];
    I2CMasterSlaveAddrSet(I2C0_BASE, LDC1314_I2C_ADDRESS, false);
    I2CMasterDataPut(I2C0_BASE, reg_addr);
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    while(I2CMasterBusy(I2C0_BASE));
    I2CMasterSlaveAddrSet(I2C0_BASE, LDC1314_I2C_ADDRESS, true);
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
    while(I2CMasterBusy(I2C0_BASE));
    rx_buffer[0] = I2CMasterDataGet(I2C0_BASE);
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
    while(I2CMasterBusy(I2C0_BASE));
    rx_buffer[1] = I2CMasterDataGet(I2C0_BASE);
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
    while(I2CMasterBusy(I2C0_BASE));
    *data = (rx_buffer[0]<<8) | rx_buffer[1];
}

static void ldc1314_cali(void)
{
    if(!ldc1314.data_base[0])
    {
        ldc1314.data_base[0] = ldc1314.data_ch[0];
        ldc1314.data_base[1] = ldc1314.data_ch[1];
        ldc1314.data_base[2] = ldc1314.data_ch[2];
        ldc1314.data_base[3] = ldc1314.data_ch[3];
    }
//     else
//     {
//         ldc1314.data_base[0] = 0;
//         ldc1314.data_base[1] = 0;
//         ldc1314.data_base[2] = 0;
//         ldc1314.data_base[3] = 0;
//     }
}
